# -*- coding:utf-8 -*-

import os
import sys
import shutil
import time
import thread
import threading
import zipfile

from MyException import Error
from MyException import GetSizeError
from MyException import NotFileError
from MyException import BigFileError
from MyException import BigZipError
from MyException import NonZipError
from MyLogger import MyLogger, SIZEROTATE, TIMEROTATE
from StatLog import StatLog
from ConfigInfo import Profile

class Receive(threading.Thread):
    def __init__(self, profile, fsinfo, zipfile_list):
        """
        初始化
        """
        #初始化线程类
        threading.Thread.__init__(self)
#        #初始化工作目录
#        self.receive_dir = profile.receive_dir 
#        self.work_dir = profile.work_dir
#        self.unzip_dir = os.path.join(profile.unzip_dir, "src")
#        #初始化内存盘最大使用率
#        self.mem_max_used = profile.mem_max_used
#        #初始化统计日志开关
#        self.is_write_statlog = profile.is_write_statlog
#        #初始化接受文件信息
#        self.file_type_list = profile.file_type_list
#        self.file_max_size = profile.file_max_size
#        self.zip_max_size = profile.zip_max_size
#        #初始化解压开关
#        self.is_unzip_file = profile.is_unzip_file
        self.profile = profile
        #初始化文件系统信息
        self.fsinfo = fsinfo
        #初始化压缩文件列表
        self.zipfile_list = zipfile_list
#        #初始化缓存和备份目录
#        self.file_cache_dir = profile.file_cache_dir
#        self.file_backup_dir = profile.file_backup_dir
        #初始化日志
        self.success_logger = MyLogger(os.path.join(profile.log_dir, "Receive_success.log"), SIZEROTATE, profile.size_rotate_backup_num)
        self.error_logger = MyLogger(os.path.join(profile.log_dir, "Receive_error.log"), SIZEROTATE, profile.size_rotate_backup_num)
        self.cache_logger = MyLogger(os.path.join(profile.log_dir, "Receive_cache.log"), SIZEROTATE, profile.size_rotate_backup_num)
        if self.profile.is_write_statlog:
            self.statlog = StatLog(profile.statlog_dir, True)
            self.statlog.daemon = True
            self.statlog.start()
#        #创建备份目录
#        os.mkdir(self.file_backup_dir)
        
    def run(self):
        """
        接受模块主函数
        """
        #处理上次未解压的文件
        zip_file_list = os.listdir(os.path.join(self.profile.unzip_dir, "src"))
        for zip_file in zip_file_list: 
            self.zipfile_list.add(zip_file)
            
        #处理接受文件
        while(True):
            try:
                #获取接受目录中文件
                file_list = os.listdir(self.profile.receive_dir)
                #获取内存盘使用率
                mem_used = self.fsinfo.mem_used
                
                #逐个处理文件
                for filename in file_list:  
                    try:
                        try:
                            #忽略临时目录
                            if filename == "temp": continue
                                
                            #拼接文件路径
                            src_file = os.path.join(self.profile.receive_dir, filename)
                            filesize = 0
                            filetype = ".--"
    
                            #判断是否是文件
                            if not os.path.isfile(src_file):
                                shutil.rmtree(src_file)
                                raise NotFileError(src_file + "is not an existing regular file")
                                                            
                            #获取文件大小
                            try:                      
                                filesize = os.path.getsize(src_file)
                            except os.error, msg:
                                raise GetSizeError(msg)
                                
                            #检查文件是否需要分发
                            is_deal_file = True
                            index = filename.rfind(".")
                            if index > -1:
                                filetype = filename[index:].lower()
                            if self.profile.file_type_list != ["all"]:  #all表示接受所有文件
                                is_deal_file = False
                                for file_type in self.profile.file_type_list:
                                    if filetype == file_type:
                                        is_deal_file = True
                                        break  
                                    
                            #print filetype, self.profile.file_type_list
                            #处理文件
                            if is_deal_file:     #需要分发文件
                                #判断文件是否超大
                                if filesize > self.profile.file_max_size:
                                    backup_dir = os.path.join(self.profile.file_backup_dir, "Big_File", time.strftime("%Y%m%d%H", time.localtime()))
                                    if not os.path.exists(backup_dir):
                                        os.makedirs(backup_dir)
                                    dst_file = os.path.join(backup_dir, filename)
                                    shutil.move(src_file, dst_file)
                                    raise BigFileError(src_file + "is a big file")
                                if mem_used < self.profile.mem_max_used:    #内存盘使用率小于最大值
                                    if self.profile.is_unzip_file and filetype == ".zip":    #满足解压要求，移动文件到解压目录
                                        #判断是否是ZIP文件
                                        if not zipfile.is_zipfile(src_file):
                                            backup_dir = os.path.join(self.profile.file_backup_dir, "Error_Zip", time.strftime("%Y%m%d%H", time.localtime()))
                                            if not os.path.exists(backup_dir):
                                                os.makedirs(backup_dir)
                                            dst_file = os.path.join(backup_dir, filename)
                                            shutil.move(src_file, dst_file)
                                            raise NonZipError(src_file + "is not zip file")
                                        #计算ZIP源文件大小
                                        zf = zipfile.ZipFile(src_file, "r")
                                        info_list = zf.infolist()
                                        total_size = 0
                                        for info in info_list:
                                            total_size += info.file_size
                                        #判断源文件是否超大
                                        if total_size > self.profile.zip_max_size:
                                            backup_dir = os.path.join(self.profile.file_backup_dir, "Big_File", time.strftime("%Y%m%d%H", time.localtime()))
                                            if not os.path.exists(backup_dir):
                                                os.makedirs(backup_dir)
                                            dst_file = os.path.join(backup_dir, filename)
                                            shutil.move(src_file, dst_file)
                                            raise BigZipError(src_file + "is a big zip file")
                                        #移动ZIP文件到解压目录
                                        dst_file = os.path.join(self.profile.unzip_dir, "src", filename)
                                        shutil.move(src_file, dst_file)
                                        self.zipfile_list.add(filename)
                                        self.success_logger.info("Success receive file: %s size: %d to: %s "%(filename, filesize, self.profile.unzip_dir))  
                                    else:   #不满足解压要求，移动文件到工作目录
                                        dst_file = os.path.join(self.profile.work_dir, filename)
                                        shutil.move(src_file, dst_file)
                                        self.success_logger.info("Success receive file: %s size: %d to: %s "%(filename, filesize, self.profile.work_dir))
                                    if self.profile.is_write_statlog:
                                        self.statlog.write_statlog_curtly(filename, filesize, filetype[1:], 0, "receive", "")
                                else:   #内存盘使用率大于最大值，缓存文件   
                                    if self.profile.is_unzip_file and filetype == ".zip":    #满足解压要求，移动文件到解压目录
                                        #判断是否是ZIP文件
                                        if not zipfile.is_zipfile(src_file):
                                            backup_dir = os.path.join(self.profile.file_backup_dir, "Error_Zip", time.strftime("%Y%m%d%H", time.localtime()))
                                            if not os.path.exists(backup_dir):
                                                os.makedirs(backup_dir)
                                            dst_file = os.path.join(backup_dir, filename)
                                            shutil.move(src_file, dst_file)
                                            raise NonZipError(src_file + "is not zip file")
                                        #计算ZIP源文件大小
                                        zf = zipfile.ZipFile(src_file, "r")
                                        info_list = zf.infolist()
                                        total_size = 0
                                        for info in info_list:
                                            total_size += info.file_size
                                        #判断源文件是否超大
                                        if total_size > self.profile.zip_max_size:
                                            backup_dir = os.path.join(self.profile.file_backup_dir, "Big_File", time.strftime("%Y%m%d%H", time.localtime()))
                                            if not os.path.exists(backup_dir):
                                                os.makedirs(backup_dir)
                                            dst_file = os.path.join(backup_dir, filename)
                                            shutil.move(src_file, dst_file)
                                            raise BigZipError(src_file + "is a big zip file")   
                                    cache_dir = os.path.join(self.profile.file_cache_dir, time.strftime("%Y%m%d%H", time.localtime()))
                                    if not os.path.exists(cache_dir): #创建缓存目录
                                        os.makedirs(cache_dir)
                                    dst_file = os.path.join(cache_dir, filename)
                                    shutil.move(src_file, dst_file)
                                    self.cache_logger.info("Success cache file: %s size: %d to: %s"%(filename, filesize, cache_dir))
                                    if self.profile.is_write_statlog:
                                        self.statlog.write_statlog_curtly(filename, filesize, filetype[1:], -1, "receive", "")                                      
                            else:   #不需要分发文件，直接删除
                                os.remove(src_file)
                                self.error_logger.info("Error receive file: %s size: %d cause: NotDeal"%(filename, filesize))
                                if self.profile.is_write_statlog:
                                    self.statlog.write_statlog_curtly(filename, filesize, filetype[1:], -1, "receive", "")
                                                                       
                        except NotFileError, msg:
                            self.error_logger.info("Error receive file: %s size: %d cause: NotFile"%(filename, filesize))
                            raise
                        except GetSizeError, msg:
                            self.error_logger.info("Error receive file: %s size: %d cause: GetSize"%(filename, filesize))
                            raise
                        except BigFileError, msg:
                            self.error_logger.info("Error receive file: %s size: %d cause: BigFile"%(filename, filesize))
                            raise
                        except BigZipError, msg:
                            self.error_logger.info("Error receive file: %s size: %d cause: BigZip"%(filename, filesize))
                            raise
                        except NonZipError, msg:
                            self.error_logger.info("Error receive file: %s size: %d cause: NonZip"%(filename, filesize))
                            raise
                        except Exception, msg:
                            self.error_logger.exception("unknown error occur where receive file %s"%(filename))
                            raise Error("unknown error")
                        
                    except Error, msg:
                        if self.profile.is_write_statlog:
                            self.statlog.write_statlog_curtly(filename, filesize, filetype[1:], -1, "receive", "")
                                                      
            except:
                self.error_logger.exception("unknown error")
                raise
            time.sleep(1)
    
import unittest
import logging
import logging.config
from ConfigReader import ConfigReader
from ConfigAssist import ConfigAssist
from MutexList import MutexList
from FSInfo import FSInfo
from StatLog import StatLog  

class ReceiveTestCase(unittest.TestCase):
    def setUp(self):
        profile = ConfigReader().read_profile()

        alL_app_conf, result = ConfigAssist().check_match_rule()
        
        self.zipfile_list = MutexList()
        fsinfo = FSInfo()
        
        if not os.path.exists(profile.receive_dir):
            os.makedirs(profile.receive_dir)
        if not os.path.exists(profile.receive_tmp_dir):
            os.makedirs(profile.receive_tmp_dir)
        if not os.path.exists(profile.work_dir):
            os.makedirs(profile.work_dir)
        if not os.path.exists(profile.unzip_dir):
            os.makedirs(profile.unzip_dir)
        if not os.path.exists(profile.file_cache_dir):
            os.makedirs(profile.file_cache_dir)
        if not os.path.exists(profile.file_backup_dir):
            os.makedirs(profile.file_backup_dir)
            
        receive_success = logging.getLogger("receive_success")
        receive_error = logging.getLogger("receive_error")
        receive_cache = logging.getLogger("receive_cache")
        
        receive_statlog_write = StatLog(profile.log_dir, True)
        receive_statlog_write.daemon = True
        receive_statlog_write.start()
    
        self.receive_thread = Receive(profile, fsinfo, self.zipfile_list, receive_success, receive_error, receive_cache, receive_statlog_write)
        
    def tearDown(self):
        pass
        
    def test_base_fun(self):
        self.receive_thread.deamon = True
        self.receive_thread.start()
        while self.receive_thread.is_alive():
            print self.zipfile_list.copy()
            time.sleep(10)
        
if __name__ == "__main__":
    suite = unittest.TestSuite()
    suite.addTest(ReceiveTestCase("test_base_fun"))   
    runner = unittest.TextTestRunner()
    runner.run(suite)